package chjob

import (
	"fmt"
	"log"
	"net/http"
)

/* 1. GMP模型原理，包括work stealing机制、hand off机制（同步系统调用）、netpoller
G: goroutine，go协程，参与调度任务，可以是函数。
M：系统级线程，系统线程的抽象，封装，协程最终要在M上运行。
P：Processor，虚拟处理器，包含运行go协程的资源，，有自己的本地队列（长度256）存放要运行的G，需要和M绑定到一起才能运行G，P的数量决定最大可并行运行多少G，，可以通过参数runtime.GOMAXPROCS()设置P的数量。
调度流程：
1、开始通过go func()创建协程G，加入到P的本地队列。
2、如果P队列都满了，则加入到全局队列中等待P本地队列有空闲后从全局队列获取。
3、P要运行G需要先和M进行绑定，P只能绑定一个M，如果有休眠的M则从休眠M队列获取M绑定，如果没有则创建一个M进行绑定运行G。
4、绑定M后，M调度P队列中的G，执行G若没有发生阻塞则运行完G后进行销毁返回，继续运行其他G。如果M运行G时发生了阻塞，则P会和发生阻塞的M进行解绑，阻塞的M等到阻塞完成可以执行后会优先找之前绑定的P加入到队列，如果之前的P已经有其他M绑定，则会加入到其他P的本地队列，本地队列都满的话会加入到全局队列等待P获取该G运行。
5、M的数量>=p的数量，阻塞释放的空闲M会加入休眠M队列等待P绑定，而不是立即释放
work stealing机制：偷机制，当都一个P本地队列没有可运行的G，会尝试从其他线程绑定的P偷取G，会优先从全局队列获取，全局队列没有则从其他P队列偷取一半G到本地P队列。
hand off机制：当P和M绑定运行G发生阻塞时，M会释放绑定的P，和M解绑后的P会绑定其他空闲的M继续运行本地队列的G，之前阻塞的G结束阻塞后会优先回到原来的P中，如果不行会加入一个空闲的P队列，都没有空闲的则加入到全局队列，阻塞结束后的M此时也是空闲的加入到休眠M队列中。
*/
/*2. GO语言中通道、类型及特点
通道底层是一个先进先出的环形队列。
类型：
	nil类型：没有初始化，只要操作就会阻塞
	非缓冲类型：容量为0的通道，同步通道，通道发送第一个元素时没有接收操作就会发生阻塞，直到被接收。同样接收元素时没有收到也会发生阻塞，直到数据发送过来。
	缓冲类型：容量不为0的通道，通道已经满再发送数据会发生阻塞，接收数据通道为空会发生阻塞。
特点：
	单向通道，通道是只能读或者只能写的通道。
	通道可以关闭，只能发送数据的一方可以关闭通道，意味着没有数据要发送了，通道关闭后可以读为读完的数据，数据读完后再读取会发生错误返回零值。
*/

// 3. 使用Go语言完成WebServer基本功能代码，并能使用浏览器访问到网页。请简述浏览器发起请求到看到网页的整个过程
/*
输入url地址回车请求后请求建立TCP连接，（http和https基于TCP连接），发起http请求，请求中包含请求头和请求体，请求头包含请求类型，cookie、请求路径等信息，请求体包含请求的内容。服务器处理请求，服务器把响应内容，请求头，状态码等信息封装成报文传输返回，浏览器通过渲染响应数据，将html、css、js等代码解析到页面显示，最终看到网页。
*/

func HelloWorld(w http.ResponseWriter, r *http.Request) {
	n, err := fmt.Fprintf(w, "Hello World")
	if err != nil {
		fmt.Println(err, n)
	}
}

func RunServer() {
	http.HandleFunc("/", HelloWorld)

	fmt.Println("Starting server on :8080")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}
}
